#令牌桶法，具体步骤：
'''
请求来了就计算生成的令牌数，生成的速率有限制
如果生成的令牌太多，则丢弃令牌
有令牌的请求才能通过，否则拒绝
'''
import redis
import time
from taotao.libs.redis_pool import POOL
from django.conf import settings
def can_pass_token_bucket(time_zone=settings.TIMEZONE, times=settings.TIMES):
    """
    :param time_zone: 接口限制的时间段
    :param times: 限制的时间段内允许多少请求通过
    """
    redis_conn = redis.Redis(connection_pool=POOL)
    # 请求来了就开始生成令牌，生成令牌速率有限制
    # key = '{}:{}'.format(user, action)
    key = "usergoods"  # 接口在redis中的key值
    # 设置一个过期时间免得占空间
    redis_conn.expire(key, time_zone + 1)

    rate = times / time_zone # 令牌生成速度
    # 上次令牌生成时间
    last_time = redis_conn.hget(key, 'last_time')
    now = time.time()
    #分析：若redis中没有last_time,则设置last_time=now,默认当前令牌数为桶容量
    last_time = last_time.decode('utf-8') if last_time else now
    # print("last_time",last_time)
    redis_conn.hset(key, 'last_time', last_time)
    time_different =float(now-float(last_time))
    capacity = times  # 桶容量
    tokens_bucket = redis_conn.hget(key, 'tokens_bucket')  # 看桶中有多少令牌
    if not tokens_bucket:
        tokens_bucket = capacity
        redis_conn.hset(key, 'tokens_bucket', tokens_bucket) #设置redis 中令牌数为桶容量
    else:
        tokens_bucket = int(tokens_bucket.decode('utf-8'))

    # 经过一段时间后生成的令牌
    delta_tokens = int(time_different * rate)  #生成的令牌数
    # print("生成的令牌数:",delta_tokens)
    if delta_tokens > 1:
        tokens_bucket = tokens_bucket + delta_tokens # 总令牌= 当前令牌+生成的令牌
        if tokens_bucket > capacity:
            tokens_bucket = capacity
        last_time = time.time() # 记录令牌生成时间
        redis_conn.hset(key, 'last_time', last_time)
    if tokens_bucket >= 1:
        tokens_bucket -= 1 # 请求进来了，令牌就减少1
        redis_conn.hset(key, 'tokens_bucket', tokens_bucket)
        print("当前桶中令牌数:", tokens_bucket)
        return True
    print("当前桶中令牌数:", tokens_bucket)
    return False


'''
令牌桶法限制的是请求的平均流入速率，优点是能应对一定程度上的突发请求，
也能在一定程度上保持流量的来源特征，实现难度不高，适用于大多数应用场景。
'''